<script setup>
import { STLLoader } from "three/addons/loaders/STLLoader.js";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
class threeCustom {
  constructor(containerId, options = {}) {
    // 合并配置参数
    this.options = {
      backgroundColor: 0x111111,
      lightIntensity: 0.8,
      modelColor: 0x00ff00,
      ...options,
    };

    // 初始化核心Three.js组件
    this.container = document.getElementById(containerId);
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(
      75,
      this.container.clientWidth / this.container.clientHeight,
      0.1,
      1000
    );
    this.renderer = new THREE.WebGLRenderer({ antialias: true });

    // 设置渲染器
    this.renderer.setSize(
      this.container.clientWidth,
      this.container.clientHeight
    );
    this.renderer.setClearColor(this.options.backgroundColor);
    this.container.appendChild(this.renderer.domElement);

    // 初始化控制器
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.camera.position.z = 50;

    // 初始化光源系统
    this.initLighting();

    // 绑定事件
    this.bindEvents();
    this.animate();
  }

  // 初始化光源
  initLighting() {
    this.ambientLight = new THREE.AmbientLight(
      0xffffff,
      this.options.lightIntensity * 0.5
    );
    this.scene.add(this.ambientLight);

    this.directionalLight = new THREE.DirectionalLight(
      0xffffff,
      this.options.lightIntensity
    );
    this.directionalLight.position.set(5, 5, 5);
    this.scene.add(this.directionalLight);
  }

  // 绑定窗口变化事件
  bindEvents() {
    window.addEventListener("resize", () => this.handleResize());
  }

  // 修改窗口resize处理
  handleResize() {
    this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
    
    // 窗口变化时重新适配模型
    if (this.currentMesh) {
      this.autoFitModel();
    }
  }

  async loadSTL(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        try {
          // 清理旧模型
        //   this.clearScene();

          // 解析STL
          const loader = new STLLoader();
          const geometry = loader.parse(e.target.result);

          // 创建材质和网格
          const material = new THREE.MeshPhongMaterial({
            color: this.options.modelColor,
            specular: 0x111111,
            shininess: 200,
          });

          this.currentMesh = new THREE.Mesh(geometry, material);
          geometry.center();
          geometry.computeVertexNormals();

          
          // 关键修改点：自适应缩放和相机定位
          this.autoFitModel(); // 替换原来的 autoScaleModel()
          this.scene.add(this.currentMesh);
          this.controls.reset();
          resolve(this.currentMesh);
        } catch (error) {
          reject(error);
        }
      };
      reader.onerror = (e) => reject(e);
      reader.readAsArrayBuffer(file);
    });
  }

  // 新增自适应方法
  autoFitModel(padding = 1.2) {
    const box = new THREE.Box3().setFromObject(this.currentMesh);
    const size = box.getSize(new THREE.Vector3());
    const center = box.getCenter(new THREE.Vector3());

    // 计算最佳缩放比例
    const maxDimension = Math.max(size.x, size.y, size.z);
    const containerHeight = this.container.clientHeight;
    const fov = this.camera.fov * (Math.PI / 180); // 转弧度
    const distance = Math.abs((maxDimension * padding) / Math.sin(fov / 2));

    // 设置相机位置
    this.camera.position.copy(center).add(new THREE.Vector3(0, 0, distance));
    this.camera.lookAt(center);

    // 更新控制器
    this.controls.target.copy(center);
    this.controls.update();
  }

  // 清空场景中的模型
  clearScene() {
    this.scene.children
      .filter((obj) => obj.isMesh)
      .forEach((mesh) => {
        mesh.geometry.dispose();
        mesh.material.dispose();
        this.scene.remove(mesh);
      });
  }

  // 动画循环
  animate() {
    this.animationFrameId = requestAnimationFrame(() => this.animate());
    this.controls.update();
    this.renderer.render(this.scene, this.camera);
  }

  // 销毁实例
  destroy() {
    cancelAnimationFrame(this.animationFrameId);
    this.clearScene();
    this.renderer.dispose();
    this.container.removeChild(this.renderer.domElement);
    window.removeEventListener("resize", this.handleResize);
  }
}

function fileChange(event) {
  const threeInstance = new threeCustom("mc");
  Array.from(event.target.files).forEach((file) => {
    threeInstance.loadSTL(file);
  });
}
</script>
<template>
  <div>
    选取本地STL:
    <input type="file" name="" id="" @change="fileChange" multiple />
  </div>
  <div class="mianContainer" id="mc"></div>
</template>
<style lang="scss" scoped>
.mianContainer {
  width: 100%;
  height: calc(100vh - 100px);
}
</style>
